
#include "game.h"
#include "iomanip"


//what is initialize in the game
void Game::gameInit(){

	m_changeTurn =  false;
	m_mapXPos = 0;
	m_mapYPos = 0;
	/*m_updateSpeed = 200;
	m_timer = 0;*/

	m_endGame = 0;

	mapClass.loadMap("map.txt");
	//I might want to think about checking if the file was read without error or readGameMap might not work
	readGameMap(mapClass);
	mapClass.release();

	m_checkedXPos = 0;
	m_checkedYPos = 0;

	m_whitesTurn = false;
	m_cursor = BLACK_TOKEN;
	m_currentToken = BLACK_TOKEN;
	m_enemyToken   = WHITE_TOKEN;

	m_tokenWidth = 1;
	m_tokenHeight = 1;

	m_tokenXPos = 3;
	m_tokenYPos = 3;
	m_tokenOldX = 0;
	m_tokenOldY = 0;

	m_bScore = 2;
	m_wScore = 2;
	m_addTok = 1;

}
void Game::draw()
{
	drawMap();
	drawCursor();
	
	gotoxy(18, 0);
	cout << "Game Name: Reversi";
	gotoxy(18, 1);
	cout << "Piece: is circular coin like piece with two different colors, one on each side.";
	gotoxy(18, 2);
	cout << "Game Goal: To make the majority of the pieces the players color;";
	gotoxy(18, 3);
	cout << "by turning over as many of the opponents pieces as possible.";
	
	gotoxy(18, 4);
	cout << "Controls: W - up, S - down, A - left, D - down,";
	gotoxy(18, 5);
	cout << "          H - add token";

	gotoxy(18, 6);
	cout << "Rules:  Start out with four pieces on the board. 2 black, 2 white.";
	gotoxy(18, 7);
	cout << "		 Dark moves first.";
	gotoxy(18, 8);
	cout << "1.You can only place a piece in an empty spot and only if that spot ";
	gotoxy(18, 9);
	cout << "is in such a way that an opponents piece falls between the your";
	gotoxy(18, 10);
	cout << "piece and the empty spot you wish to add your piece.";
	gotoxy(18, 11);
	cout << "2.The opponents piece that are caught in between are then flip and turned your color.";
	gotoxy(18, 13);
	cout << "3.Game ends if either player has no piece of their own or if the squares are filled.";
	gotoxy(18, 14);
	cout << "4.The player with the highest score wins.";
	gotoxy(18, 15);
	cout << "BlueToken Score: " << setw(2) << setfill('0') << m_bScore;
	gotoxy(18, 16);
	cout << "WhiteToken Score: " << setw(2) << setfill('0') << m_wScore;

	if(m_addTok == 0)
	{
		gotoxy( 18, 17);//don't forget to add function to display messages in draw
		cout << "Can't add there";
		m_addTok = 1;
	}
	else
	{
		gotoxy( 18, 17);//clears message
		cout << "                ";
	}

	if(m_endGame == 1)
	{
		if(m_bScore > m_wScore)
		{
			gotoxy(0, 19);
			cout << "BLUE TOKEN WINS!!!";
		}
		else if(m_bScore < m_wScore)
		{
			gotoxy(0, 19);
			cout << "WHITE TOKEN WINS!!!";
		}
		else
		{
			gotoxy(0, 19);
			cout << "IT IS A TIE!!!";
		}
	}
}
void Game::endCondition()
{
	bool no_WToken = true;
	bool no_BToken = true;
	bool no_emptySpace = true;
	for(int r = 3; r < m_mapHeight; r = getMoveDown(r))
	{
		for(int c = 3; c < m_mapWidth; c = getMoveRight(c))
		{
			if( m_gameMap[r][c] == 'B'){
				no_BToken = false;
			}
			if(m_gameMap[r][c] == 'W'){
				no_WToken = false;
			}
			if(m_gameMap[r][c] == ' '){
				no_emptySpace = false;
			}
		}
	}

	/*if(no_WToken == true || no_BToken == true ||no_emptySpace == true)
	{
		m_endGame = 1;
	}*/
	if(m_bScore == 0 || m_wScore == 0 || m_bScore + m_wScore == 64)
	{
		m_endGame = 1;
	}
	
}
void Game::countScore()
{
	m_bScore = 0;
	m_wScore = 0;
	for(int r = 3; r < m_mapHeight; r = getMoveDown(r))
	{
		for(int c = 3; c < m_mapWidth; c = getMoveRight(c))
		{
			if( m_gameMap[r][c] == 'B'){
				m_bScore++;
			}
			if(m_gameMap[r][c] == 'W'){
				m_wScore++;
			}
		}
	}
}
void Game::drawCursor()
{
	gotoxy(m_tokenXPos, m_tokenYPos);
	if(m_whitesTurn == true)
	{
		setcolor(COLOR_WHITE, COLOR_BLACK);
		cout << m_cursor;
	}
	else
	{
		setcolor(COLOR_BLUE, COLOR_BLACK);
		cout << m_cursor;
	}
	setcolor(COLOR_GRAY, COLOR_BLACK);
	
}
void Game::changeTurns()
{
	if (m_currentToken == BLACK_TOKEN)
	{
		m_whitesTurn = true;
		m_currentToken = WHITE_TOKEN;
		m_enemyToken = BLACK_TOKEN;
		m_cursor = WHITE_TOKEN;
	}
	else
	{
		m_whitesTurn = false;
		m_currentToken = BLACK_TOKEN;
		m_enemyToken = WHITE_TOKEN;
		m_cursor = BLACK_TOKEN;
	}
}
void Game::handleInput(char a_input)
{
	m_tokenOldX = m_tokenXPos;
	m_tokenOldY = m_tokenYPos;

	switch(a_input)
	{
	case 'w': m_tokenYPos = getMoveUp(m_tokenYPos ); break;
	case 's': m_tokenYPos = getMoveDown(m_tokenYPos ); break;
	case 'd': m_tokenXPos = getMoveRight(m_tokenXPos); break;
	case 'a': m_tokenXPos = getMoveLeft(m_tokenXPos); break;
	case 'h': addToken(); break;
	case 'p': changeTurns();

	}

}
void Game::addToken()
{
	//if current position is empty then you might be able to add
	if(overlaps(' ', m_tokenXPos, m_tokenYPos))
	{
		//function that actually checks to see if its possible to add token and flip other token
		flipTokenLogic();

		
	}
	//fucntions that changes players turn if they added a token
	if(m_changeTurn == true)
	{
		changeTurns();
		m_changeTurn = false;
	}
	else{ //if they didn't add a token then its still current players turn
		m_addTok = 0;
	}
	/*else{ 
		 m_addTok = 0;
		}*/
	


}
void Game::flipTokenLogic()
{
	//gets cursors current position
	int xPos = m_tokenXPos;
	int yPos = m_tokenYPos;

	//check  right for possible flips
	if(rightCheck())
	{
		for(int xPos = m_tokenXPos; xPos < m_checkedXPos; xPos = getMoveRight(xPos))
		{
			if(m_gameMap[yPos][xPos] != m_currentToken)
			{
				m_gameMap[yPos][xPos] = m_currentToken;
			}
		}
	}

	//check left for possible flips
	if(leftCheck())
	{
		for(int xPos = m_tokenXPos; xPos > m_checkedXPos; xPos = getMoveLeft(xPos))
		{
			if(m_gameMap[yPos][xPos] != m_currentToken)
			{
				m_gameMap[yPos][xPos] = m_currentToken;
			}
		}
	}
	
	//check up for possible flips
	if(upCheck())
	{
		for(int yPos = m_tokenYPos; yPos >  m_checkedYPos; yPos = getMoveUp(yPos))
		{
			if(m_gameMap[yPos][xPos] != m_currentToken)
			{
				m_gameMap[yPos][xPos] = m_currentToken;
			}
		}
	}
	//check down for possible flips
	if(downCheck())
	{
		for(int yPos = m_tokenYPos; yPos < m_checkedYPos; yPos = getMoveDown(yPos))
		{
			if(m_gameMap[yPos][xPos] != m_currentToken)
			{
				m_gameMap[yPos][xPos] = m_currentToken;
			}
		}
	}
	//check right up for possible flips /diagonal 
	if(RUCheck())
	{
		for(int yPos = m_tokenYPos; yPos > m_checkedYPos; yPos = getMoveUp(yPos))
		{
			if(xPos < m_mapWidth)
			{
				if(m_gameMap[yPos][xPos] != m_currentToken)
				{
					m_gameMap[yPos][xPos] = m_currentToken;
				}
				
			}
			xPos = getMoveRight(xPos);
		}
	}
	//check right down for possible flips / diagonal
	if(RDCheck())
	{
		for(int yPos = m_tokenYPos; yPos < m_checkedYPos; yPos = getMoveDown(yPos))
		{
			if(xPos < m_mapWidth)
			{
				if(m_gameMap[yPos][xPos] != m_currentToken)
				{
					m_gameMap[yPos][xPos] = m_currentToken;
				}
				
			}
			xPos = getMoveRight(xPos);
		}
	}
	//check left up for possible flips / diagonal
	if(LUCheck())
	{
		for(int yPos = m_tokenYPos; yPos > m_checkedYPos; yPos = getMoveUp(yPos))
		{
			if(xPos > m_mapXPos)
			{
				if(m_gameMap[yPos][xPos] != m_currentToken)
				{
					m_gameMap[yPos][xPos] = m_currentToken;
				}
			}
			xPos = getMoveLeft(xPos);
		}
	}
	//check left down for possible flips / diagonal
	if(LDCheck())
	{
		for(int yPos = m_tokenYPos; yPos < m_checkedYPos; yPos = getMoveDown(yPos))
		{
			if(xPos > m_mapXPos)
			{
				if(m_gameMap[yPos][xPos] != m_currentToken)
				{
					m_gameMap[yPos][xPos] = m_currentToken;
				}
			}
			xPos = getMoveLeft(xPos);
		}
	}
}
bool Game::LDCheck()
{
	int tempX = m_tokenXPos;
	int tempY = m_tokenYPos;
	if(tempY < m_mapHeight-MOVEBY && tempX > m_mapXPos+MOVEBY)
	{
		tempX = getMoveLeft(tempX);
		tempY = getMoveDown(tempY);
		if(m_gameMap[tempY][tempX] == m_enemyToken)
		{
			for(int yPos = tempY; yPos < m_mapHeight; yPos = getMoveDown(yPos))
			{
				if(tempX > m_mapXPos)
				{
					if(m_gameMap[yPos][tempX] == ' '){return false; }

					if(m_gameMap[yPos][tempX] == m_currentToken )
					{
						m_checkedXPos = tempX;
						m_checkedYPos = yPos;
						m_changeTurn = true;
						return true;
					}
				}
				tempX = getMoveLeft(tempX);
			}
		}
	}
	return false;
}
bool Game::LUCheck()
{
	int tempX = m_tokenXPos;
	int tempY = m_tokenYPos;

	if(tempY > m_mapYPos+MOVEBY && tempX > m_mapXPos+MOVEBY)
	{
		tempX = getMoveLeft(tempX);
		tempY = getMoveUp(tempY);
		if(m_gameMap[tempY][tempX] == m_enemyToken)
		{
			for(int yPos = tempY; yPos > m_mapYPos; yPos = getMoveUp(yPos))
			{
				if(tempX > m_mapXPos)
				{
					if(m_gameMap[yPos][tempX] == ' '){return false; }

					if(m_gameMap[yPos][tempX] == m_currentToken)
					{
						m_checkedXPos = tempX;
						m_checkedYPos = yPos;
						m_changeTurn = true;
						return true;
					}
				}
				tempX = getMoveLeft(tempX);
			}
		}
	}
	return false;
}
bool Game::RDCheck()
{
	int tempX = m_tokenXPos;
	int tempY = m_tokenYPos;

	if(tempY < m_mapHeight-MOVEBY && tempX < m_mapWidth-MOVEBY)
	{
		tempX = getMoveRight(tempX);
		tempY = getMoveDown(tempY);
		if(m_gameMap[tempY][tempX] == m_enemyToken)
		{
			for(int yPos = tempY; yPos < m_mapHeight; yPos = getMoveDown(yPos))
			{
				if(tempX < m_mapWidth)
				{
					if(m_gameMap[yPos][tempX] == ' '){ return false; }

					if(m_gameMap[yPos][tempX] == m_currentToken )
					{
						m_checkedXPos = tempX;
						m_checkedYPos = yPos;
						m_changeTurn = true;
						return true;
					}
					tempX = getMoveRight(tempX);
				}
			}
		}
	}
	return false;
}
bool Game::RUCheck()
{
	int tempX = m_tokenXPos;
	int tempY = m_tokenYPos;

	if(tempY > m_mapYPos+MOVEBY && tempX < m_mapWidth-MOVEBY)
	{
		tempX = getMoveRight(tempX);
		tempY = getMoveUp(tempY);
		if(m_gameMap[tempY][tempX] == m_enemyToken)
		{
			for(int yPos = tempY; yPos > m_mapYPos; yPos = getMoveUp(yPos))
			{
				if(tempX < m_mapWidth)
				{
					if(m_gameMap[yPos][tempX] == ' '){ return false; }

					if(m_gameMap[yPos][tempX] == m_currentToken )
					{
						m_checkedXPos = tempX;
						m_checkedYPos = yPos;
						m_changeTurn = true;
						return true;
					}
					tempX = getMoveRight(tempX);
				}
			}
		}
	}
	return false;
}
bool Game::downCheck()
{
	int tempX = m_tokenXPos;
	int tempY = m_tokenYPos;
	
	if(tempY < m_mapHeight-MOVEBY)
	{
		tempY = getMoveDown(tempY);
		if(m_gameMap[tempY][tempX] == m_enemyToken)
		{
			for(int yPos = tempY; yPos < m_mapHeight; yPos = getMoveDown(yPos))
			{
				if(m_gameMap[yPos][tempX] == ' '){ return false; }

				if(m_gameMap[yPos][tempX] == m_currentToken )
				{
					m_checkedYPos = yPos;
					m_changeTurn = true;
					return true;
				}
			}
		}
	}
	return false;
}
bool Game::upCheck()
{
	int tempX = m_tokenXPos;
	int tempY = m_tokenYPos;

	if(tempY > m_mapYPos+MOVEBY)
	{
		tempY = getMoveUp(tempY);
		if(m_gameMap[tempY][tempX] == m_enemyToken)
		{
			for(int yPos = tempY; yPos > m_mapYPos; yPos = getMoveUp(yPos))
			{
				if( m_gameMap[yPos][tempX] == ' '){ return false; }

				if(m_gameMap[yPos][tempX] == m_currentToken )
				{
					m_checkedYPos = yPos;
					m_changeTurn = true;
					return true;
				}
			}
		}
	}
	return false;
}
bool Game::leftCheck()
{
	int tempX = m_tokenXPos;
	int tempY = m_tokenYPos;

	if(tempX > m_mapXPos+MOVEBY)
	{
		tempX = getMoveLeft(tempX);
		if(m_gameMap[tempY][tempX] == m_enemyToken)
		{
			for(int xPos = tempX; xPos > m_mapXPos; xPos = getMoveLeft(xPos))
			{
				if(m_gameMap[tempY][xPos] == ' '){ return false; }
				if(m_gameMap[tempY][xPos] == m_currentToken)
				{
					m_checkedXPos = xPos;
					m_changeTurn = true;
					return true;
				}
			
			}
		}
	}
	return false;
}
bool Game::rightCheck()
{
	int tempX = m_tokenXPos;
	int tempY = m_tokenYPos;

	if(tempX < m_mapWidth-MOVEBY)
	{
		tempX = getMoveRight(tempX);

		if(m_gameMap[tempY][tempX] == m_enemyToken)
		{
			for(int xPos = tempX; xPos < m_mapWidth; xPos = getMoveRight(xPos))
			{
				if(m_gameMap[tempY][xPos] == ' '){ return false; }
				if(m_gameMap[tempY][xPos] == m_currentToken)
				{
					m_checkedXPos = xPos;
					m_changeTurn = true;
					return true;
				}
				
			}
		}
	}
	return false;
}

// get move functions return position you would be at in the map squares
int Game::getMoveUp(int a_y)	{ return a_y -= MOVEBY; }
int Game::getMoveDown(int a_y)	{ return a_y += MOVEBY; }
int Game::getMoveRight(int a_x){ return a_x += MOVEBY; }
int Game::getMoveLeft(int a_x)	{ return a_x -= MOVEBY; }

//checks collision against the maps borders and with other token characters
void Game::collisionCheck()
{
	if(m_tokenXPos < m_mapXPos
		|| m_tokenYPos < m_mapYPos
		|| m_tokenXPos+m_tokenWidth > m_mapXPos+m_mapWidth
		|| m_tokenYPos+m_tokenHeight > m_mapYPos+m_mapHeight
		/*|| overlaps('W', m_tokenXPos, m_tokenYPos)
		|| overlaps('B', m_tokenXPos, m_tokenYPos)*/
		)
	{
		m_tokenXPos = m_tokenOldX;
		m_tokenYPos = m_tokenOldY;
	}
}
//function that tells you if the character/value given is at the specified position
bool Game::overlaps(char a_value, int a_x, int a_y)
{
	if(m_gameMap[a_y][a_x] == a_value)
	{
		return true;
	}
	return false;
}
//funtion that reads the file to be the game map
void Game::readGameMap( Map & a){
	m_mapWidth = a.getWidth();
	m_mapHeight = a.getHeight();

	m_gameMap = new char * [m_mapHeight];
	//load the 2d mapdata into the gamemap 2d array
	for(int r = 0; r < m_mapHeight; ++r)
	{
		m_gameMap[r] = new char[m_mapWidth];
		for(int c = 0; c < m_mapWidth; ++c)
		{
			m_gameMap[r][c] = a.getMapcharacter(r,c);
		}
	}
}
//draws map
void Game::drawMap(){
	gotoxy(m_mapXPos, m_mapYPos);
	for(int r = 0; r < m_mapHeight; ++r)
	{
		for(int c = 0; c < m_mapWidth; ++c)
		{
			cout << m_gameMap[r][c] ;
		}
		cout << endl;
	}
}
//releases map
void Game::releaseMap(){
	if(m_gameMap)
	{
		for(int r = 0; r < m_mapHeight; ++r)
		{
			delete m_gameMap[r];
		}
		delete m_gameMap;

		m_gameMap = NULL;
	}
}
void Game::update(/*int a_ms*/)
{
	/*m_timer += a_ms;*/
	collisionCheck();
	/*if(m_timer >= m_updateSpeed)
	{
		m_timer -= m_updateSpeed;*/
		
		countScore();
		endCondition(); //checks to see if game has ended
	/*}*/
}